/* 
 * File:   ipd_piecewise_linear_function.cpp
 * Author: dima
 * 
 * Created on 14 Январь 2015 г., 11:53
 */

#include "ipd_exception.h"
#include "ipd_img.h"
#include "ipd_piecewise_linear_function.h"
#include <iostream>
namespace ipd
{

/*  
 * |----|----|
 * count interval=2
 * count_point=3
 */
ipd_piecewise_linear_function::ipd_piecewise_linear_function(ipd_img &img,int step_color) : image(img), step(step_color)
{
    count_intervals = ((image.get_max_color() -image.get_min_color()) / (double) step) + 1;
    count_points = count_intervals + 1;
    X = new double[count_points]; //X-axis values
    Y = new double[count_points]; //Y-axis values
    K = NULL;
    B = NULL;
}

void ipd_piecewise_linear_function::convert_image(ipd_img &convertible_image)//convert Image
{

    int width = image.get_width();
    int height = image.get_height();
    convertible_image.init(width, height, image.get_color_type());
    create_equation(); //create equation
    switch (image.get_color_type())
    {
    case tp_mono:
    {
        try
        {
            unsigned char color_pixel_old, color_pixel_new;
            for (int j = 0; j < height; j++)
            {
                for (int i = 0; i < width; i++)
                {
                    color_pixel_old = *image.get_color(i, j);
                    color_pixel_new = normalization(color_pixel_old);
                    convertible_image.set_color(i, j, &color_pixel_new);
                }
            }
        }
        catch (ipd::ipd_exception &except)
        {
            throw ipd_exception(except.what(), except.in_file());
        }
        break;
    }
    case tp_RGB:
    {
        try
        {
            unsigned char *color_pixel_old;
            unsigned char ch;
            unsigned char color_pixel_new[sz_RGB];
            for (int j = 0; j < height; j++)
            {
                for (int i = 0; i < width; i++)
                {
                    color_pixel_old = image.get_color(i, j);
                    for (int p = 0; p < sz_RGB; p++)
                    {
                        ch = *(color_pixel_old + p);
                        color_pixel_new[p] = normalization(ch);
                    }
                    convertible_image.set_color(i, j, color_pixel_new);
                }
            }
        }
        catch (ipd::ipd_exception &except)
        {
            throw ipd_exception(except.what(), except.in_file());
        }
        break;
    }
    default:
    {
        throw ipd_exception(std::string("Image model is not supported (Supports RGB and monochrome image)"), std::string("ipd_equalization"));
    }
    }

}

ipd_piecewise_linear_function::~ipd_piecewise_linear_function()
{
    delete_KB();
    delete X;
    delete Y;
}

void ipd_piecewise_linear_function::set_value(int index, double x, double y) //set value
{
    if (index < 0 || index >= count_points)
    {
        throw ipd_exception(std::string("The index value is set incorrectly"), std::string("ipd_piecewise_linear_function"));
    }
    if (x > image.get_max_color() || x < image.get_min_color())
    {
        throw ipd_exception(std::string("The X value is set incorrectly"), std::string("ipd_piecewise_linear_function"));
    }
    if (y > image.get_max_color() || y < image.get_min_color())
    {
        throw ipd_exception(std::string("The X value is set incorrectly"), std::string("ipd_piecewise_linear_function"));
    }
    X[index] = x;
    Y[index] = y;
}

void ipd_piecewise_linear_function::get_value(int index, double &x, double &y) //get value
{
    if (index < 0 || index >= count_points)
    {
        throw ipd_exception(std::string("The index value is set incorrectly"), std::string("ipd_piecewise_linear_function"));
    }
    x = X[index];
    y = Y[index];
}

void ipd_piecewise_linear_function::delete_KB() //delete coefficients of the line
{
    if (K != NULL)
        delete []K;
    K = NULL;
    if (B != NULL)
        delete []B;
    B = NULL;
}

void ipd_piecewise_linear_function::create_equation()//Creating an equation for direct interpolation values
{
    delete_KB();
    K = new double [count_intervals];
    B = new double [count_intervals];
    for (int i = 0; i < count_intervals; i++)
    {
        K[i] = (Y[i + 1] - Y[i]) / (X[i + 1] - X[i]);
        B[i] = (Y[i] * X[i + 1] - Y[i + 1] * X[i]) / (X[i + 1] - X[i]);
    }
}

unsigned char ipd_piecewise_linear_function::normalization(double value)
{
    unsigned char result;
    int interval = (value / (double) step);
    result = K[interval] * value + B[interval];
    result = result < image.get_min_color() ? image.get_min_color() : result; // normalization
    result = result > image.get_max_color() ? image.get_max_color() : result; // normalization

    return result;
}

ipd_piecewise_linear_function::ipd_piecewise_linear_function(const ipd_piecewise_linear_function& orig) : image(orig.image), step(orig.step)
{

}

}